import { onMounted, isRef, reactive, computed } from 'vue'
import { ElNotification, ElMessageBox } from 'element-plus'

export default function useCrud(options = {}) {
  const defaultOptions = {
    // 标题
    title: '',
    // 表格数据
    data: [],
    // 选择项
    selections: [],
    // hooks
    hooks: {},
    // API Service
    apiService: {
      list: (params) => {},
      add: (data) => {},
      edit: (data) => {},
      delete: (ids) => {},
      get: (id) => {},
      export: (params) => {}
    },
    // 自定义扩展属性
    props: {
      searchVisible: true, // 搜索栏是否可见
      searchFormVisible: true, // 搜索表单是否可见
    }
  }

  const fieldOptions = {
    // id字段
    idField: 'id',
    // 列表字段
    rowsField: 'rows',
    // 当前页码字段
    pageField: 'page',
    // 每页大小字段
    sizeField: 'size',
    // 数据总数字段
    totalField: 'total',
    // 操作提醒字段
    promptField: 'id'
  }

  const queryOptions = {
    // 查询参数
    queryParams: {},
    // 查询等待时间
    time: 50,
    // 页面加载后，自动查询
    autoQuery: true
  }

  const pageOptions = {
    // 当前页码
    page: 1,
    // 分页大小
    size: 10,
    // 数据总数
    total: 0
  }

  const refOptions = {
    // Form 表单
    form: {},
    // Form 引用
    formRef: null,
    // Table引用
    tableRef: null
  }

  // 合并配置选项
  const mergedOptions = mergeOptions({ ...defaultOptions, ...fieldOptions, ...queryOptions, ...pageOptions, ...refOptions }, options)

  const data = {
    ...mergedOptions,
    // 记录初始数据，后续重置时使用
    defaultQueryParams: JSON.parse(JSON.stringify(isRef(options.queryParams) ? options.queryParams.value : options.queryParams)),
    defaultForm: JSON.parse(JSON.stringify(isRef(options.form) ? options.form.value : options.form)),
    // 优化后的状态管理
    crudType: null, // 当前CRUD操作类型：'list' | 'add' | 'edit' | 'delete' | null
    crudStatus: CRUD.STATUS.NORMAL, // 当前CRUD操作状态
    exportStatus: CRUD.STATUS.NORMAL // 导出操作独立状态
  }

  // crud响应式对象
  const crud = reactive({
    ...data,
    /* 动态属性管理 */
    // 动态标题
    formTitle: computed(() => {
      const { title, crudType, crudStatus } = crud
      
      // 标题映射配置
      const titleMap = {
        [CRUD.TYPE.ADD]: `新增${title}`,
        [CRUD.TYPE.EDIT]: `编辑${title}`,
        [CRUD.TYPE.DELETE]: `删除${title}`,
        [CRUD.TYPE.EXPORT]: `导出${title}`
      }
      
      // 根据当前操作类型和状态返回对应标题
      if (crudType && crudStatus > CRUD.STATUS.NORMAL) {
        return titleMap[crudType] || `查看${title}`
      }
      
      return `查看${title}`
    }),
    // 表单操作状态（添加或编辑）
    formStatus: computed(() => ['add', 'edit'].includes(crud.crudType) ? crud.crudStatus : CRUD.STATUS.NORMAL),
    // 判断是否表单对话框可见
    formVisible: computed(() => crud.formStatus !== CRUD.STATUS.NORMAL),
    // 判断是否选中
    hasSelection: computed(() => crud.selections?.length > 0),
    // 判断是否查询中
    loading: computed(() => crud.crudType === CRUD.TYPE.LIST && crud.crudStatus === CRUD.STATUS.PROCESSING),
    // 判断是否提交中
    commitLoading: computed(() => crud.formStatus === CRUD.STATUS.PROCESSING),
    // 判断是否删除中
    deleteLoading: computed(() => crud.crudType === CRUD.TYPE.DELETE && crud.crudStatus === CRUD.STATUS.PROCESSING),
    // 判断是否导出中
    exportLoading: computed(() => crud.exportStatus === CRUD.STATUS.PROCESSING)
  })

  // hook VM - 支持同步和异步钩子
  const callVmHook = async (hook, ...args) => {
    try {
      const hooks = crud.hooks
      if (hooks && typeof hooks[hook] === 'function') {
        const result = hooks[hook].apply(crud, args)
        // 检查是否为 Promise
        if (result && typeof result.then === 'function') {
          const asyncResult = await result
          return asyncResult !== false
        }
        return result !== false
      }
      return true
    } catch (error) {
      console.error(`Hook ${hook} execution failed:`, error)
      return false
    }
  }

  /** methods */

  /**
   * 刷新
   */
  const handleRefresh = () => {
    crud.page = 1
    doQuery()
  }
  
  /**
   * 清空查询条件
   * @param {Boolean} toQuery 清空后进行查询操作
   * @param {Boolean} useDefaultQueryParams 是否使用默认查询参数
   */
  const handleClear = (toQuery = true, useDefaultQueryParams = true) => {
    const { defaultQueryParams, queryParams } = crud

    Object.keys(queryParams).forEach((key) => {
      queryParams[key] = useDefaultQueryParams ? defaultQueryParams[key] : null
    })

    if (toQuery) {
      crud.page = 1
      doQuery()
    }
  }

  /**
   * 查询
   */
  const handleQuery = () => {
    doQuery()
  }

  /**
   * 添加
   */
  const handleAdd = async () => {
    resetForm()

    if (!((await callVmHook('beforeToAdd')) && (await callVmHook('beforeToCU')))) {
      return
    }

    setStatus(CRUD.TYPE.ADD, CRUD.STATUS.PREPARED)
    await callVmHook('afterToAdd')
    await callVmHook('afterToCU')
  }

  /**
   * 编辑
   * @param {*} data 数据项
   */
  const handleEdit = async (data) => {
    // 处理PointerEvent参数：如果第一个参数是事件对象，则忽略它
    if (data && (data instanceof Event || data.type || data.target)) {
      data = null
    }
    
    data = data || crud.selections[0]
    if (!data) {
      notifyError('请选择数据再编辑')
      return
    }

    resetForm(JSON.parse(JSON.stringify(data)))

    if (!((await callVmHook('beforeToEdit')) && (await callVmHook('beforeToCU')))) {
      return
    }

    setStatus(CRUD.TYPE.EDIT, CRUD.STATUS.PREPARED)
    await callVmHook('afterToEdit')
    await callVmHook('afterToCU')
  }

  /**
   * 删除
   * @param {Object} row 数据项
   */
  const handleDelete = (data) => {
    // 处理PointerEvent参数：如果第一个参数是事件对象，则忽略它
    if (data && (data instanceof Event || data.type || data.target)) {
      data = null
    }
    
    data = data ? [data] : crud.selections
    if (!data || data.length === 0) {
      notifyError('请选择要删除的数据')
      return
    }

    setStatus(CRUD.TYPE.DELETE, CRUD.STATUS.PREPARED)

    const promptVals = data.map((val) => getPromptDataVal(val))
    const promptText = `确认删除${crud.promptField}为"${promptVals}"的数据？`

    ElMessageBox.confirm(promptText)
      .then(() => {
        doDelete(data)
      })
      .catch(() => {
        setStatus(CRUD.TYPE.DELETE, CRUD.STATUS.NORMAL)
      })
  }

  /**
   * 导出
   */
  const handleExport = () => {
    doExport()
  }

  /**
   * 新增/编辑 取消
   */
  const handleCancel = async () => {
    if (!(await callVmHook('beforeCancel'))) {
      return
    }

    resetForm()
    setStatus(crud.crudType, CRUD.STATUS.NORMAL)
    await callVmHook('afterCancel')
  }

  /**
   * 新增/编辑 提交
   */
  const handleSubmit = async () => {
    if (!(await callVmHook('beforeValidate'))) {
      return
    }

    crud.formRef?.validate().then(async (validateResult) => {
      // TDesign: validateResult 值为 true 表示校验通过；如果校验不通过，validateResult 值为校验结果列表。
      if (validateResult !== true) {
        return
      }

      if (!(await callVmHook('afterValidate'))) {
        return
      }

      doSubmit()
    })
  }

  /**
   * 执行查询
   */ 
  const doQuery = async () => {
    if (!(await callVmHook('beforeQuery'))) {
      return
    }

    setStatus(CRUD.TYPE.LIST, CRUD.STATUS.PROCESSING)

    try {
      // 请求数据
      const data = await crud.apiService.list(getQueryParams())

      crud.total = data[crud.totalField] || 0
      crud.data = data[crud.rowsField] || data

      // time 毫秒后显示数据
      setTimeout(() => {
        setStatus(CRUD.TYPE.LIST, CRUD.STATUS.NORMAL)
        callVmHook('afterQuery').catch(error => {
          console.error('afterQuery hook execution failed:', error)
        })
      }, crud.time)
    } catch(error) {
      setStatus(CRUD.TYPE.LIST, CRUD.STATUS.NORMAL)
      await callVmHook('afterQueryError', error)
      notifyError(`查询失败：${error.message || '未知错误'}`)
      console.error('查询失败：', error)
    }
  }

  /**
   * 执行提交
   */
  const doSubmit = async () => {
    if (!(await callVmHook('beforeSubmit'))) {
      return
    }

    const { crudType, formTitle, form } = crud
    setStatus(crudType, CRUD.STATUS.PROCESSING)

    try {
      // 构建提交表单 commitForm
      const data = Object.fromEntries(
        Object.entries(form).map((item) => {
          if (item[1] && typeof item[1] === 'object' && !Array.isArray(item[1]) && !getDataId(item[1])) {
            item[1] = null
          }
          return item
        })
      )

      await crud.apiService[crudType](data)
      resetForm()
      setStatus(crudType, CRUD.STATUS.NORMAL)
      await callVmHook('afterSubmit')
      notifySuccess()
      doQuery()
    } catch(error) {
      setStatus(crudType, CRUD.STATUS.PREPARED)
      await callVmHook('afterSubmitError')
      notifyError(`${formTitle}失败：${error.message || '未知错误'}`)
      console.error(`${formTitle}失败：`, error)
    }
  }

  /**
   * 执行删除
   * @param {Array} datas 数据项
   */
  const doDelete = async (datas) => {
    if (!(await callVmHook('beforeDelete', datas))) {
      return
    }
    
    setStatus(CRUD.TYPE.DELETE, CRUD.STATUS.PROCESSING)

    try {
      const ids = datas.map((val) => getDataId(val))
      await crud.apiService.delete(ids)
      setStatus(CRUD.TYPE.DELETE, CRUD.STATUS.NORMAL)
      await callVmHook('afterDelete', datas)
      notifySuccess()
      doQuery()
    } catch(error) {
      setStatus(CRUD.TYPE.DELETE, CRUD.STATUS.PREPARED)
      await callVmHook('afterDeleteError', datas)
      notifyError(`删除${crud.title}失败：${error.message || '未知错误'}`)
      console.error(`删除${crud.title}失败：`, error)
    }
  }
 
  /**
   * 执行导出
   */
  const doExport = async () => {
    if (!(await callVmHook('beforeExport'))) {
      return
    }
    
    setStatus(CRUD.TYPE.EXPORT, CRUD.STATUS.PROCESSING)

    try {
      await crud.apiService.export(getQueryParams())
      setStatus(CRUD.TYPE.EXPORT, CRUD.STATUS.NORMAL)
      await callVmHook('afterExport')
    } catch(error) {
      setStatus(CRUD.TYPE.EXPORT, CRUD.STATUS.PREPARED)
      await callVmHook('afterExportError')
      notifyError(`导出失败：${error.message || '未知错误'}`)
      console.error('导出失败：', error)
    }
  }

  /**
   * 获取查询参数
   */
  const getQueryParams = () => {
    // 清除无值的参数
    const { queryParams, pageField, sizeField, page, size } = crud
    const params = { ...queryParams }
    for (let key in params) {
      if (params[key] === null || params[key] === '') {
        params[key] = undefined
      }
    }
    return {
      ...params,
      [pageField]: page,
      [sizeField]: size
    }
  }

  /**
   * 当前页码改变
   * @param {number} current 当前页码
   */
  const handlePageChange = (current) => {
    crud.page = current
    doQuery()
  }

  /**
   * 分页大小改变
   * @param {number} size 每页大小
   */
  const handleSizeChange = (size) => {
    crud.page = 1
    crud.size = size
    doQuery()
  }

  /**
   * 选中项改变
   * @param {Array} selections 选中项
   */
  const handleSelectionChange = (selections) => {
    crud.selections = selections
  }

  /**
   * 重置表单
   * @param {Array} data 表单数据
   */
  const resetForm = (data = crud.defaultForm) => {
    Object.keys(crud.form).forEach((key) => {
      crud.form[key] = data[key]
    })

    // 清除表单验证
    crud.formRef?.clearValidate()
  }

  /**
   * 设置操作状态
   * @param {String | Number} type 操作类型
   * @param {Number} status 操作状态
   */
  const setStatus = (type, status) => {
    if (type === 'export') {
      crud.exportStatus = status
    } else {
      // 核心CRUD操作互斥
      if (status === CRUD.STATUS.NORMAL) {
        crud.crudType = null
        crud.crudStatus = CRUD.STATUS.NORMAL
      } else {
        crud.crudType = type
        crud.crudStatus = status
      }
    }
  }

  /**
   * 用于树形表格多选, 选中所有
   * @param {Array} selections 选中项
   */
  const handleTreeSelectionAllChange = (selections) => {
    // 如果选中的数目与请求到的数目相同就选中子节点，否则就清空选中
    if (selections && selections.length === crud.data.length) {
      selections.forEach((val) => {
        handleTreeSelectionChange(selections, val)
      })
    } else {
      getTable().clearSelection()
    }
  }

  /**
   * 用于树形表格多选，单选的封装
   * @param {Array} selections 选中项
   * @param {Object} row 行数据
   */
  const handleTreeSelectionChange = (selections, row) => {
    // 如果selections中存在row代表是选中，否则是取消选中
    if (selections.find((val) => getDataId(val) === getDataId(row))) {
      if (row.children) {
        row.children.forEach((val) => {
          getTable().toggleRowSelection(val, true)
          selections.push(val)
          if (val.children) {
            handleTreeSelectionChange(selections, val)
          }
        })
      }
    } else {
      toggleRowSelection(selections, row)
    }
  }

  /**
   * 用于树形表格单选，切换选中状态
   * @param {Array} selections 选中项
   * @param {Object} row 行数据
   */
  const toggleRowSelection = (selections, row) => {
    if (row.children) {
      row.children.forEach((val) => {
        getTable().toggleRowSelection(val, false)
        if (val.children) {
          toggleRowSelection(selections, val)
        }
      })
    }
  }
  
  /**
   * 成功通知
   * @param {String} message 成功消息
   */
  const notifySuccess = (message = '操作成功') => {
    notify(message, CRUD.NOTIFICATION_TYPE.SUCCESS)
  }

  /**
   * 失败通知
   * @param {String} message 失败消息
   */
  const notifyError = (message = '操作失败') => {
    notify(message, CRUD.NOTIFICATION_TYPE.ERROR)
  }

  /**
   * 消息通知
   * @param {String} message 消息内容
   * @param {String} type 
   */
  const notify = (message, type = CRUD.NOTIFICATION_TYPE.INFO) => {
    ElNotification[type]({
      title: message,
      duration: 2500
    })
  }

  const getDataId = (data) => {
    return data[crud.idField]
  }

  const getPromptDataVal = (data) => {
    return data[crud.promptField]
  }

  const getTable = () => {
    return crud.tableRef
  }

  const methods = {
    handleRefresh,
    handleClear,
    handleQuery,
    handleAdd,
    handleEdit,
    handleDelete,
    handleExport,
    handleCancel,
    handleSubmit,
    handlePageChange,
    handleSizeChange,
    handleSelectionChange,
    handleTreeSelectionChange,
    handleTreeSelectionAllChange,
    doQuery,
    doSubmit,
    doDelete,
    doExport,
    getQueryParams,
    notifySuccess,
    notifyError,
    notify
  }

  // 附加方法
  Object.assign(crud, methods)

  onMounted(() => {
    if (crud.autoQuery) {
      doQuery()
    }
  })

  return crud
}

function mergeOptions(src, opts) {
  if (!src || !opts) return src || opts

  const optsRet = { ...src }
  for (const key in opts) {
    if (key in src) {
      optsRet[key] = opts[key]
    }
  }
  return optsRet
}

export const CRUD = {
  // CRUD 类型
  TYPE: {
    LIST: 'list',
    ADD: 'add',
    EDIT: 'edit',
    DELETE: 'delete',
    EXPORT: 'export'
  },
  // CRUD 状态
  STATUS: {
    NORMAL: 0,
    PREPARED: 1,
    PROCESSING: 2
  },
  // NOTIFICATION_TYPE
  NOTIFICATION_TYPE: {
    SUCCESS: 'success',
    WARNING: 'warning',
    INFO: 'info',
    ERROR: 'error'
  }
}
